/*************************************************************************
    > File Name: relay.c
    > Author: ma6174
    > Mail: ma6174@163.com 
    > Created Time: 2022年01月13日 星期四 18时55分06秒
 ************************************************************************/

#include<stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#define FNAME1 "/dev/tty11"
#define FNAME2 "/dev/tty12"
#define BUFSIZE 1024
#define ERRSIZE 60
#include <errno.h>
#include <string.h>
#include <poll.h>

enum {
	STATE_R=1,
	STATE_W,
STATE_AUTO,
	STATE_EX,
	STATE_T,
};
struct fsm_st{
	int state;
	int sfd;
	int dfd;
	char buf[BUFSIZE];
	int len;
	char ch[ERRSIZE];
	int err;
};

static void fsm_driver(struct fsm_st* fsm){
	int ret;
	int ret1=0;
	switch (fsm->state){
		case STATE_R:
			ret=read(fsm->sfd,fsm->buf,BUFSIZE);
			if(ret<0){
				if(errno==EAGAIN){
					fsm->state=STATE_R;
				}
				else{
					fsm->state=STATE_EX;
					strncpy(fsm->ch,"read",ERRSIZE);
					fsm->err=errno;
				}
			}
			else if(ret==0){
				fsm->state=STATE_R;
			}
			else {
				fsm->state=STATE_W;
				fsm->len=ret;
				ret1=0;
			}
			break;
		case STATE_W:
			ret1=write(fsm->dfd,fsm->buf+ret1,fsm->len);
			if(ret1<0){
				if(errno=EAGAIN){
					fsm->state=STATE_W;
				}
				else{
					fsm->state=STATE_EX;
					strncpy(fsm->ch,"write",ERRSIZE);
					fsm->err=errno;
				}
			}
			else{
				fsm->len-=ret1;
				if(fsm->len==0){
					fsm->state=STATE_R;
				}
				else{
					fsm->state=STATE_W;
				}
			}
			break;
		case STATE_EX:fprintf(stderr,"%s\n",strerror(fsm->err));
					  fprintf(stderr,"%s\n",fsm->ch);
					  fsm->state=STATE_T;
			break;
		case STATE_T:/*exit(1)*/
			break;
		default:abort();
	}
}

static int max(int x,int y){
	return x>y?x:y;
}


static void relay(int fd1,int fd2){
	int fd1_save,fd2_save;
	fd1_save=fcntl(fd1,F_GETFL);
	fd2_save=fcntl(fd2,F_GETFL);
	fcntl(fd1,F_SETFL,fd1_save|O_NONBLOCK);
	fcntl(fd2,F_SETFL,fd2_save|O_NONBLOCK);
	struct fsm_st fsm12,fsm21;
	fsm12.state=STATE_R;
	fsm12.sfd=fd1;
	fsm12.dfd=fd2;	
	fsm21.state=STATE_R;
	fsm21.sfd=fd2;
	fsm21.dfd=fd1;
	

	struct pollfd pfd[2];
	pfd[0].fd=fd1;
	pfd[1].fd=fd2;

	while(fsm12.state!=STATE_T||fsm21.state!=STATE_T){
		//布置监视任务

		pfd[0].events=0;
		pfd[1].events=0;

		if(fsm12.state==STATE_R){
			pfd[0].events|=POLLIN;
		}
		if(fsm21.state==STATE_W){
			pfd[0].events|=POLLOUT;
		}
		if(fsm12.state==STATE_W){
			pfd[1].events|=POLLOUT;
		}
		if(fsm21.state==STATE_R){
			pfd[1].events|=POLLIN;
		}
		

		//监视
		
		if(fsm12.state<STATE_AUTO||fsm21.state<STATE_AUTO){
			while(poll(pfd,2,-1)<0){
				if(errno==EINTR)
					continue;
				perror("poll()");
				exit(1);
			}
		}
		//查看监视结果

		if(pfd[0].revents&POLLIN || pfd[1].revents&POLLOUT \
				|| fsm12.state>STATE_AUTO)
		fsm_driver(&fsm12);
		if(pfd[1].revents&POLLIN || pfd[0].revents&POLLOUT \
				||fsm21.state>STATE_AUTO)
		fsm_driver(&fsm21);
	}


	fcntl(fd1,F_SETFL,fd1_save);
	fcntl(fd2,F_SETFL,fd2_save);

	
}



int main(){
	int fd1,fd2;
	fd1=open(FNAME1,O_RDWR);
	if(fd1<0){
		perror("open()1");
		exit(1);
	}
	fd2=open(FNAME2,O_RDWR|O_NONBLOCK);
	if(fd2<0){
		close(fd1);
		perror("open()2");
		exit(1);
	}
	write(fd1,"tty11\n",6);
	write(fd2,"tty12\n",6);

	relay(fd1,fd2);

	close(fd2);
	close(fd1);


	exit(0);
}


